package com.bootdo.cash.service.impl;

import static com.bootdo.common.utils.ShiroUtils.getUserId;

import java.text.DecimalFormat;
import java.util.Date;
import java.util.List;
import java.util.Map;

import org.apache.commons.codec.binary.Base64;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import com.alibaba.fastjson.JSONObject;
import com.bootdo.cash.dao.CashDao;
import com.bootdo.cash.domain.CashDO;
import com.bootdo.cash.service.CashService;
import com.bootdo.cash.util.CashRedis;
import com.bootdo.common.config.Constant;
import com.bootdo.common.redis.lock.CommonRedisLock;
import com.bootdo.common.utils.DateUtils;
import com.bootdo.common.utils.ExceptionUtils;
import com.bootdo.common.utils.StringUtils;
import com.bootdo.common.utils.UploadUtils;
import com.bootdo.merchant.dao.AgentDao;
import com.bootdo.merchant.dao.MerchantDao;
import com.bootdo.merchant.domain.AgentDO;
import com.bootdo.merchant.domain.MerchantDO;
import com.bootdo.mq.RabbitUtil;
import com.bootdo.order.dao.OrderPayDao;
import com.bootdo.order.dao.RechargeDao;
import com.bootdo.order.domain.RechargeDO;
import com.bootdo.quota.dao.QuotaDao;
import com.bootdo.quota.domain.QuotaDO;
import com.bootdo.system.dao.UserRoleDao;

/**
 * @Desc
 * @date 2019/12/13
 *
 */
@Service
public class CashServiceImpl implements CashService {

    private static final Logger logger = LoggerFactory.getLogger(CashServiceImpl.class);

    @Autowired
    private CashDao cashMapper;
    @Autowired
    private UserRoleDao userRoleMapper;
    @Autowired
    private RechargeDao rechargeMapper;
    @Autowired
    private AgentDao agentMapper;
    @Autowired
    private MerchantDao merchantMapper;
    @Autowired
    private CashRedis cashRedis;
    @Autowired
    private QuotaDao quotaMapper;
    @Autowired
    private OrderPayDao orderPayMapper;

    @Autowired
    private RabbitUtil rabbitUtil;

    @Autowired
    protected StringRedisTemplate stringRedisTemplate;


    @Value("${bootdo.uploadPath}")
    private String url;
    @Value("${bootdo.path}")
    private String paths;

    @Override
    public CashDO get(Long userId){
        return cashMapper.get(userId);
    }

    /**
     * 获取提现列表
     * @param map
     * @return
     */
    @Override
    public List<CashDO> list(Map<String, Object> map){
        //格式话日期
        String startDate = (String) map.get("startTime");
        String endDate = (String) map.get("endTime");
        if (StringUtils.isNotBlank(startDate)){
            startDate = DateUtils.getDateOfFormatByYMD(startDate, DateUtils.DATE_PATTERN_YMD,DateUtils.DATE_B_TIME_PATTERN);
            endDate = DateUtils.getDateOfFormatByYMD(endDate, DateUtils.DATE_PATTERN_YMD,DateUtils.DATE_E_TIME_PATTERN);
            map.put("startTime", startDate);
            map.put("endTime", endDate);
        }
        Long userId = getUserId();
        //获取用户权限
        int checkUserIsManager = userRoleMapper.checkUserIsManager(userId);
        if (checkUserIsManager != 1){
            map.put("userId", userId);
        }
        return cashMapper.list(map);
    }

    /**
     * 获取发起人备注
     * @param userId
     * @return
     */
    @Override
    public String findUser(Long userId) {
        String name = "平台";
        //获取用户权限
        List<Long> list = userRoleMapper.listRoleId(userId);
        for (Long roleId : list){
            if (roleId == 60L) {
                //商户代理
                AgentDO agent = agentMapper.get(userId);
                name = agent.getRemarks();
                break;
            } else if (roleId == 62L) {
                //商户
                MerchantDO merchant = merchantMapper.get(userId);
                name = merchant.getRemarks();
                break;
            }
        }
        return name;
    }

    /**
     * 获取当前商户可提现金额
     * @param merchantId
     * @return
     */
    @Override
    public Double findMerchantMoney(Long merchantId){
        CommonRedisLock commonLock = new CommonRedisLock(stringRedisTemplate,"findMerchantMoney"+merchantId);
        try {
            if (commonLock.tryLock(3)) {
                //获取当前用户信息
                QuotaDO quota = quotaMapper.get(merchantId);
                long money = Math.round(quota.getActualQuota() * 100);
                logger.debug("当前用户【"+merchantId+"】实际额度："+money);
                DecimalFormat df = new DecimalFormat("0.00");
                logger.debug("当前用户【"+merchantId+"】可提现金额："+df.format((float)(money)/100));
                commonLock.unlock();
                return Double.valueOf(df.format((float)(money)/100));
            }
        } catch (Exception e) {
            logger.error("=====获取当前商户可提现金额异常=====>" + ExceptionUtils.getStackTraceAsString(e));
            commonLock.unlock();
            return 0.0;
        }
        return 0.0;
    }

    /**
     * 获取平台可提现金额
     * @return
     */
    @Override
    public Double findPlatformMoney() {
        CommonRedisLock commonLock = new CommonRedisLock(stringRedisTemplate,"findPlatformMoney"+getUserId());
        try {
            if (commonLock.tryLock(3)) {
                long money = Math.round(orderPayMapper.queryOrderMoney() * 100);
                //获取用户权限
                int checkUserIsManager = userRoleMapper.checkUserIsManager(getUserId());
                if (checkUserIsManager != 1){
                    QuotaDO quota = quotaMapper.get(getUserId());
                    money = Math.round(quota.getActualQuota() * 100);
                }

                logger.debug("======订单可提现金额======>" + money);
                //获取当前商户已申请提现金额
                DecimalFormat df = new DecimalFormat("0.00");
                commonLock.unlock();
                return Double.valueOf(df.format((float)(money)/100));
            }
        } catch (Exception e) {
            logger.error("=====获取平台可提现金额异常=====>" + ExceptionUtils.getStackTraceAsString(e));
            commonLock.unlock();
            return 0.0;
        }
        return 0.0;
    }

    /**
     * 获取提现列表总条数
     * @param map
     * @return
     */
    @Override
    public int count(Map<String, Object> map){
        return cashMapper.count(map);
    }

    /**
     * 新增提现
     * @param cash
     * @return
     */
    @Override
    @Transactional(propagation = Propagation.REQUIRED,isolation = Isolation.DEFAULT,timeout=36000,rollbackFor=Exception.class)
    public int save(CashDO cash){
        CommonRedisLock commonLock = new CommonRedisLock(stringRedisTemplate,"CASH_SAVE_"+getUserId());
        try {
            if (commonLock.tryLock(3)) {
                int count = 0;
                String cashFlag = cashRedis.get("cash" + cash.getUserId());
                if (StringUtils.isBlank(cashFlag) || "0".equals(cashFlag)) {
                    cashRedis.set("cash" + cash.getUserId(), "1");
                    double money = orderPayMapper.queryOrderMoney();
                    int checkUserIsManager = userRoleMapper.checkUserIsManager(getUserId());
                    if (checkUserIsManager != 1) {
                        QuotaDO quota = quotaMapper.get(getUserId());
                        money = quota.getActualQuota();
                    }
                    if (money >= cash.getCashMoney()) {
                        cash.setUserId(getUserId());
                        cash.setGmtCreate(new Date());
                        cash.setStatus(0);
                        count = cashMapper.save(cash);
                        JSONObject object = new JSONObject();
                        object.put("date", DateUtils.format(new Date(), DateUtils.DATE_TIME_PATTERN));
                        object.put("orderId", "TC0001");
                        object.put("type", 2);
                        object.put("reason", "提现锁定金额");
                        object.put("money", cash.getCashMoney());
                        object.put("userId", cash.getUserId());
                        rabbitUtil.sendToQueue(Constant.UPDATE_QUOTA, object.toJSONString());
                    } else {
                        count = -2;
                    }
                    cashRedis.set("cash" + cash.getUserId(), "0");
                }
                commonLock.unlock();
                return count;
            }
        } catch (Exception e) {
            logger.error("=====新增提现异常=====>" + ExceptionUtils.getStackTraceAsString(e));
            commonLock.unlock();
            return 0;
        }
        return 0;
    }

    @Override
    @Transactional(propagation = Propagation.REQUIRED,isolation = Isolation.DEFAULT,timeout=36000,rollbackFor=Exception.class)
    public int update(CashDO cash){
        return cashMapper.update(cash);
    }

    @Override
    @Transactional(propagation = Propagation.REQUIRED,isolation = Isolation.DEFAULT,timeout=36000,rollbackFor=Exception.class)
    public int updateExamine(CashDO cash){
        CashDO cashs = cashMapper.get(cash.getId());
        if(0 == cashs.getStatus()) {
            //提现申请审核不通过，则将商户余额回调上去
            if (3 == cash.getStatus().intValue()){
                long cashMoney = Math.round(cashs.getCashMoney() * 100);
                long actualArrival = Math.round(cashs.getActualArrival() * 100);
                long lockingMoney = Math.round(cashs.getLockingMoney() * 100);
                DecimalFormat df = new DecimalFormat("0.00");
                Double money = Double.valueOf(df.format((float)(cashMoney - actualArrival - lockingMoney)/100));

                JSONObject object = new JSONObject();
                object.put("date", DateUtils.format(new Date(), DateUtils.DATE_TIME_PATTERN));
                object.put("orderId", "TC0001");
                object.put("type", 1);
                object.put("reason", "提现审核不通过恢复");
                object.put("money", money);
                object.put("userId", cashs.getUserId());
                rabbitUtil.sendToQueue(Constant.UPDATE_QUOTA, object.toJSONString());
            }
            return cashMapper.update(cash);
        }
        return 0;
    }

    @Override
    public RechargeDO upload(byte[] b, String fileType) {
        //将凭证转为base64
        String base64 = Base64.encodeBase64String(b);
        //将文件存储在临时文件集合中
        String key = Constant.FILE + StringUtils.getUUIDStr(10);
        Constant.MAP.put(key, base64);
        RechargeDO recharge = new RechargeDO();
        recharge.setVoucher(key);
        recharge.setVoucherType(fileType);
        recharge.setVouchers(base64.trim());
        return recharge;
    }

    @Override
    @Transactional(propagation = Propagation.REQUIRED,isolation = Isolation.DEFAULT,timeout=36000,rollbackFor=Exception.class)
    public int rechargeSave(RechargeDO recharge) {
        CommonRedisLock commonLock = new CommonRedisLock(stringRedisTemplate, "RECHARGE_SAVE_" + recharge.getCashId());
        try {
            if (commonLock.tryLock(3)) {
                String cashFlag = cashRedis.get("cash" + recharge.getCashId());
                if (StringUtils.isBlank(cashFlag) || "0".equals(cashFlag)) {
                    cashRedis.set("cash" + recharge.getCashId(), "1");
                } else if ("1".equals(cashFlag)) {
                    return -3;
                } else {
                    return -4;
                }
                if (recharge.getMoney() == null) {
                    return -5;
                } else {
                    if (recharge.getMoney().doubleValue() <= 0.0) {
                        return -6;
                    } else {
                        CashDO cash = cashMapper.get(recharge.getCashId());
                        long money = Math.round(cash.getCashMoney() * 100);
                        long actual = Math.round(cash.getActualArrival() * 100);
                        long lock = Math.round(cash.getLockingMoney() * 100);
                        long moneys = Math.round(recharge.getMoney() * 100);
                        if ((money - actual - lock) >= moneys) {
                            String fileName = StringUtils.getUUIDStr(20).toLowerCase();
                            if (StringUtils.isBlank(recharge.getVoucherType())) {
                                recharge.setVoucherType("png");
                            }
                            fileName += "." + recharge.getVoucherType();
                            String path = UploadUtils.upload(url, fileName, "3", Constant.MAP.get(recharge.getVoucher()));
                            recharge.setVoucher(paths + path);

                            recharge.setCashUserId(cash.getUserId());
                            recharge.setUserId(getUserId());
                            recharge.setGmtCreate(new Date());
                            recharge.setStatus(0);
                            int count = rechargeMapper.save(recharge);
                            //锁定金额
                            cash = new CashDO();
                            cash.setId(recharge.getCashId());
                            DecimalFormat df = new DecimalFormat("0.00");
                            double locking = Double.valueOf(df.format((float) (moneys + lock) / 100));
                            cash.setLockingMoney(locking);
                            cash.setStatus(0);
                            cashMapper.update(cash);
                            cashRedis.set("cash" + recharge.getCashId(), "0");
                            return count;
                        } else {
                            cashRedis.set("cash" + recharge.getCashId(), "0");
                            return -2;
                        }
                    }
                }
            }
        } catch (Exception e) {
            logger.error("=====保存支付异常=====>" + ExceptionUtils.getStackTraceAsString(e));
            return 0;
        } finally {
            commonLock.unlock();
        }
        return 0;
    }
}
